package com.upay.android.controller.fragment;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.codehaus.jackson.type.TypeReference;

import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.upay.android.R;
import com.upay.android.controller.adapter.WeightedPaymentArrayAdapter;
import com.upay.android.controller.helper.Format;
import com.upay.android.controller.policy.WeightedPaymentResultMappingPolicy;
import com.upay.android.core.service.RestService;
import com.upay.android.domain.authentication.AuthenticationToken;
import com.upay.android.domain.group.GroupAccount;
import com.upay.android.domain.payment.PaymentList;
import com.upay.android.domain.payment.WeightedPaymentDetail;
import com.upay.android.domain.request.ProtectedRequestHeader;
import com.upay.android.domain.request.RequestBody;
import com.upay.android.domain.request.RequestEnvelope;
import com.upay.android.domain.response.EmptyResponse;
import com.upay.android.domain.response.ResponseEnvelope;
import com.upay.android.domain.rest.RestRequest;
import com.upay.android.util.rest.UrlHelper;

public class WeightedPaymentFragment extends AbstractFragment {

	/* ---- Constants ---- */


	/* ---- Instance Variables ---- */
	private PaymentList<WeightedPaymentDetail> mPaymentList = null;
	private ListView mTransactionsField = null;
    private OnWeightedPaymentTotalRequestedListener mCallback;
    private TextView mTransactionTotalField = null;
    private Button mTotalButton = null;
    private GroupAccount mGroupAccount = null;

	/* ---- Constructors ---- */
	
	/* ---- Business Methods ---- */
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getContext().setTitle(R.string.weighted_payment_title);
		setHasOptionsMenu(true);
        mPaymentList = new PaymentList<WeightedPaymentDetail>(new ArrayList<WeightedPaymentDetail>());
	}
		

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_weighted_payment_group_transaction, parent, false);
        //mPaymentList.payments.clear();
        mTransactionTotalField = (TextView)view.findViewById(R.id.value_weighted_payment_transaction_total);
        mTransactionsField = (ListView)view.findViewById(R.id.list_weighted_payment_transactions);
        mTransactionsField.setChoiceMode(ListView.CHOICE_MODE_SINGLE);  
        mTotalButton = (Button)view.findViewById(R.id.button_weighted_payment_transaction_total);
        mTotalButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View view) {				
				WeightedPaymentResultMappingPolicy policy = new WeightedPaymentResultMappingPolicy(
					mPaymentList, mPaymentList.getSelectedPayment().getGroupAccount().getUser());
				mCallback.onPaymentTotalRequested(policy);
			}
		});
        
        getLoaderManager().initLoader(0, null, new WeightedPaymentLoader());		
        updateTransactionTotal();
        return view; 
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    	inflater.inflate(R.menu.weightedpaymentmenu, menu);
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	switch(item.getItemId()) {
    	case android.R.id.home:
    		getContext().finish();
    		break;
    	case R.id.action_weighted_payment_confirm_transaction:
    		doFinalizeTransaction();
    		break;
    	case R.id.action_weighted_payment_refresh:
    		getLoaderManager().restartLoader(0, null, new WeightedPaymentFragment.WeightedPaymentLoader());
    		break;
    	default:
    		return super.onOptionsItemSelected(item);	
    	}
    	return true;
    }
 
    private void doFinalizeTransaction() {
    	if (mPaymentList.getTransactionValue().equals(new BigDecimal(0)) || ((this.totalWeight(mPaymentList.payments)).compareTo(new BigDecimal(0)) == 0)) {
    		getContext().showValidationErrors("Please set an amount and weight.", Gravity.CENTER);
    	} else {
    		getLoaderManager().initLoader(1, null, new WeightedPaymentFragment.WeightedPaymentSender());
    	}

    }
    
	public BigDecimal totalWeight(List<WeightedPaymentDetail> payments) {
		BigDecimal total = new BigDecimal(0);
		for (WeightedPaymentDetail paymentDetail : payments) {
			total = total.add(paymentDetail.getWeightValue());
		}
		return total;
	}
    
    public void updateTransactionTotal() {
    	mTransactionTotalField.setText(Format.format(mPaymentList.getTransactionValue()));
    }
	
    /* ---- Getters and Setters ---- */
    
	public GroupAccount getGroupAccount() {
		return mGroupAccount;
	}

	public void setGroupAccount(GroupAccount groupAccount) {
		this.mGroupAccount = groupAccount;
	}

	/* ---- Interfaces ---- */

    // Container Activity must implement this interface
    public interface OnWeightedPaymentTotalRequestedListener {
    	public void onPaymentTotalRequested(WeightedPaymentResultMappingPolicy policy);
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnWeightedPaymentTotalRequestedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnWeightedPaymentTotalRequestedListener");
        }
    }
    
    /* ---- Inner Classes ---- */
    
    private class WeightedPaymentLoader implements LoaderCallbacks<ResponseEnvelope<List<WeightedPaymentDetail>>> {

    	@Override
    	public Loader<ResponseEnvelope<List<WeightedPaymentDetail>>> onCreateLoader(int id, Bundle bundle) {
    		AuthenticationToken authenticationToken = getAuthenticationToken();
    		RequestEnvelope<ProtectedRequestHeader, GroupAccount> requestEnvelope = 
    				new RequestEnvelope<ProtectedRequestHeader, GroupAccount>(
    					new ProtectedRequestHeader(authenticationToken), 
    					new RequestBody<GroupAccount>(mGroupAccount));
    		TypeReference<ResponseEnvelope<List<WeightedPaymentDetail>>> typeReference = new TypeReference<ResponseEnvelope<List<WeightedPaymentDetail>>>() {};
    		RestRequest<ProtectedRequestHeader, GroupAccount, List<WeightedPaymentDetail>> restRequest = 
    				new RestRequest<ProtectedRequestHeader, GroupAccount, List<WeightedPaymentDetail>>(
    					UrlHelper.getUrl(getResources(), UrlHelper.GET_WEIGHTED_PAYMENT_DETAILS),
    					requestEnvelope,
    					typeReference);           	    
    		RestService<ProtectedRequestHeader, GroupAccount, List<WeightedPaymentDetail>> restService =
    				new RestService<ProtectedRequestHeader, GroupAccount, List<WeightedPaymentDetail>>(
    					getActivity().getApplicationContext(),
    					restRequest);
    		return restService;
    	}
	

    	@Override
    	public void onLoadFinished(Loader<ResponseEnvelope<List<WeightedPaymentDetail>>> loader, ResponseEnvelope<List<WeightedPaymentDetail>> responseEnvelope) {
    		System.out.println(loader.isStarted());
    		System.out.println(loader.isAbandoned());
    		System.out.println(loader.takeContentChanged());
    		if (!responseEnvelope.getResponseHeader().getStatus()) {
    			getContext().handleError(responseEnvelope.getResponseBody().getResponseError());
    		} else {		
    			mPaymentList.payments.clear();
    			for (WeightedPaymentDetail paymentDetail : responseEnvelope.getResponseBody().getResponseObject()) {
    				mPaymentList.add(paymentDetail);
    				if (mPaymentList.getSelectedPayment() == null) {
    					mPaymentList.setSelectedPayment(paymentDetail);
    					paymentDetail.setSelected(Boolean.TRUE);
    				}
    			}

    			WeightedPaymentArrayAdapter adapter = new WeightedPaymentArrayAdapter(getContext(), mPaymentList);  			
    			mTransactionsField.setAdapter(adapter);
    			updateTransactionTotal();
    		}
    	}

    	@Override
    	public void onLoaderReset(Loader<ResponseEnvelope<List<WeightedPaymentDetail>>> loader) {
    	}
	
    } // end class

    private class WeightedPaymentSender implements LoaderCallbacks<ResponseEnvelope<EmptyResponse>> {

    	@Override
    	public Loader<ResponseEnvelope<EmptyResponse>> onCreateLoader(int id, Bundle bundle) {
    		AuthenticationToken authenticationToken = getAuthenticationToken();
    		RequestEnvelope<ProtectedRequestHeader, PaymentList<WeightedPaymentDetail>> requestEnvelope = 
    			new RequestEnvelope<ProtectedRequestHeader, PaymentList<WeightedPaymentDetail>>(
    				new ProtectedRequestHeader(authenticationToken), 
    				new RequestBody<PaymentList<WeightedPaymentDetail>>(mPaymentList));
    		TypeReference<ResponseEnvelope<EmptyResponse>> typeReference = new TypeReference<ResponseEnvelope<EmptyResponse>>() {};
    		RestRequest<ProtectedRequestHeader, PaymentList<WeightedPaymentDetail>, EmptyResponse> restRequest = 
    			new RestRequest<ProtectedRequestHeader, PaymentList<WeightedPaymentDetail>, EmptyResponse>(
    				UrlHelper.getUrl(getResources(), UrlHelper.SAVE_WEIGHTED_PAYMENT_DETAILS), 
    				requestEnvelope, 
    				typeReference);           	    
    		RestService<ProtectedRequestHeader, PaymentList<WeightedPaymentDetail>, EmptyResponse> restService =
    			new RestService<ProtectedRequestHeader, PaymentList<WeightedPaymentDetail>, EmptyResponse>(
    				getActivity().getApplicationContext(), restRequest);
    		return restService;
    	}
	

    	@Override
    	public void onLoadFinished(Loader<ResponseEnvelope<EmptyResponse>> loader, ResponseEnvelope<EmptyResponse> responseEnvelope) {
    		if (!responseEnvelope.getResponseHeader().getStatus()) {
    			getContext().handleError(responseEnvelope.getResponseBody().getResponseError());
    		} else {		
        		getContext().finish();
    		}
    	}

    	@Override
    	public void onLoaderReset(Loader<ResponseEnvelope<EmptyResponse>> loader) {
    	}
	
    } // end class
	
}

